"""
@Project ：PythonInterfaceFrame 
@File    ：conftest.py
@IDE     ：PyCharm 
@Author  ：张成龙
@Date    ：2024/10/12 10:09 
@explain ：
"""
import os.path
import logging
import os
import re
from logging import handlers
import subprocess
import time
import shutil

import psutil

from utils.LoadEnvUtil import LoadEnvUtil
from utils.SendMsgToWorkWeiXin import SendMsgToWorkWeiXin

# 项目根路径
# BASE_DIR = os.path.dirname(__file__)
BASE_DIR = os.path.abspath(os.path.dirname(__file__))


# 配置日志文件
# 初始化日志配置
def init_log_config():
    # 创建日志器
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    # 创建控制台处理器
    sh = logging.StreamHandler()

    # 创建文件处理器
    # 文件路径
    # Create file processor
    # File path
    log_dir = os.path.join(BASE_DIR, "log")
    os.makedirs(log_dir, exist_ok=True)  # 如果不存在就创建，存在就跳过
    log_path = os.path.join(log_dir, "log.log")

    fh = logging.handlers.TimedRotatingFileHandler(log_path, when="midnight", interval=1,
                                                   backupCount=7, encoding="UTF-8")
    # 创建格式化器
    f = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"
    formatter = logging.Formatter(f)

    # 把格式化处理器添加到处理器当中
    sh.setFormatter(formatter)
    fh.setFormatter(formatter)

    # 把处理器添加到日志器当中
    logger.addHandler(sh)
    logger.addHandler(fh)


"""
pytest_terminal_summary 是 Pytest 的一个内置钩子函数，它允许你在测试会话结束时，定制化地输出总结信息到终端
这一方法在 Pytest 测试运行完成后被调用，适用于添加额外统计信息、运行结果分析或其他总结性输出
在终端执行 pytest 命令之后 测试会话结束时触发以下条件
执行上传测试报告到文档中心
企业微信通知相关人员并统计测试数据(用例总数、失败用例数、成功用例数、跳过用例数、运行会话耗时、点击跳转文档中心地址)

参数 exitstatus :
    0 所有测试通过
    1 至少有一个测试用例失败
    2 测试用例未被正确收集(可能是语法错误 文件路径错误等问题)
    3 用户手动中断测试执行
    4 pytest 的命令行参数错误
    5 pytest 未找到测试用例

"""

# 企业微信机器人 webhook
webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + LoadEnvUtil.get_env_params("WEBHOOK")
# 通知描述
desc = "xxx项目接口自动化数据汇总"
# 通知企业微信人员 list 集合
# 艾特某一个人填入其手机号即可  @all表示艾特所有人 不需要可以去掉 ["15093643240", "@all"]
# notifier = ["15093643240"]
# 文档中心测试报告跳转地址
# address = LoadEnvUtil.get_env_params("DOCUMENT_CENTER")


def pytest_configure(config):
    """
    初始化 Pytest 运行时共享数据。
    """
    # 记录会话开始时间
    config.start_time = time.time()


def run_allure_server(results_dir):
    """后台启动 allure serve 服务"""
    allure_path = shutil.which("allure")
    if not allure_path:
        raise RuntimeError("找不到 allure 命令，请确认环境变量已配置，或手动设置 allure 路径。")
    # cmd = [allure_path, "serve", "-h", "0.0.0.0", "-p", str(port), results_dir]
    # subprocess.Popen(cmd)
    cmd = [allure_path, "serve", results_dir]
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
    pattern = re.compile(r"http://[^\s]+:\d+/")
    address = None

    # 监听输出
    while True:
        line = process.stdout.readline()
        if not line:
            break
        print(f"[Allure] {line.strip()}")  # 打印日志
        match = pattern.search(line)
        if match:
            address = match.group(0)
            break

    return address


def kill_allure_serve():
    """查找并杀掉已有 allure serve 进程"""
    for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
        try:
            if 'allure' in proc.info['name'] or \
               (proc.info['cmdline'] and 'serve' in proc.info['cmdline']):
                print(f"[INFO] 发现旧 Allure 进程，已终止 PID: {proc.pid}")
                proc.kill()
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue


def pytest_terminal_summary(terminalreporter, exitstatus):
    """在 Pytest 会话结束时计算总耗时并统计结果"""
    end_time = time.time()
    # 用 config 共享的 start_time
    total_time = round(end_time - terminalreporter.config.start_time, 2)  # 保留两位小数的总耗时
    # 控制台的输出时间包括pytest插件加载 插件运行 测试用例运行 钩子函数运行 等所有时间综合
    # 在此统计的仅仅是 pytest 会话执行前后时间 不包括插件加载 失败重跑 钩子函数运行完毕的时间
    print(f"\n仅测试会话运行耗时: {total_time:.2f} 秒")
    print("\n==== pytest 会话结束 ====")

    # 获取测试结果统计
    stats = terminalreporter.stats

    skipped_tests = len(stats.get("skipped", []))  # 跳过测试数量
    failed_tests = len(stats.get("failed", []))    # 失败测试数量
    passed_tests = len(stats.get("passed", []))    # 成功测试数量
    total_tests = passed_tests + failed_tests + skipped_tests  # 总测试数量

    print("\n==== 测试统计 ====")
    print(f"总测试用例数量: {total_tests}")
    print(f"成功: {passed_tests}")
    print(f"失败: {failed_tests}")
    print(f"跳过: {skipped_tests}")

    # 根据不同的退出状态输出不同的信息
    if exitstatus == 0:
        print("所有测试通过！")
    elif exitstatus == 1:
        print("有测试失败，请检查日志！")
    elif exitstatus == 2:
        print("测试用例未被正确收集，请检查路径或语法错误！")
    elif exitstatus == 3:
        print("测试被手动中断！")
    else:
        print("未知错误，请检查配置或环境问题。")

    # 启动 Allure 服务
    try:
        print("\n正在检查是否有旧的 Allure 进程...")
        kill_allure_serve()

        results_dir = "./report/allure-data"  # 你的报告路径
        print("\n启动 Allure 报告服务中...")
        # 获取局域网访问地址
        address = run_allure_server(results_dir)
        print(f"Allure 报告地址: {address}")
    except Exception as e:
        print(f"启动 Allure 报告失败: {e}")
        address = "Allure 服务启动失败"

    """
    企业微信通知
    """
    try:
        open_notifier = LoadEnvUtil.get_env_params("OPEN_OFFICER_NOTIFICATION", "false").lower()
        if open_notifier == "true":
            # 通知企业微信结果
            SendMsgToWorkWeiXin().send_test_results_msg(webhook, desc, total_tests, passed_tests, failed_tests,
                                                        skipped_tests, total_time, address)
            notifier = LoadEnvUtil.parse_notifier_officer("NOTIFIER_OFFICER", "@all")
            # 企业微信通知具体人员
            SendMsgToWorkWeiXin().send_notifying_officer(webhook, notifier)
    except Exception as e:
        print(f"企业微信通知失败, 错误信息: {e}")

